#include <typescommon.h>
#include <genrand.h>
#include <pthread.h>
#include <rbtree_option.h>

// c没有把这些基本数据结构写入标准库中。可能是因为c++有了。
// 二叉树。左小右大规则。但是可能出现线性树。
// 前序遍历，中序遍历，后序遍历。

// 平衡二叉树。每个节点到叶节点深度不超过1.

// 完全二叉树。每一层要依次排满。但实现难。

// 红黑树：
// 性质1. 结点是红色或黑色。 [3]
// 性质2. 根结点是黑色。 [3]
// 性质3. 所有叶子都是黑色。（叶子是NIL结点） [3]
// 性质4. 每个红色结点的两个子结点都是黑色。（从每个叶子到根的所有路径上不能有两个连续的红色结点）
// 性质5. 从任一结点到其每个叶子的所有路径都包含相同数目的黑色结点。 [3]

#define rbtreeCheckSize 10
int rbSampleCompareUint(const void *keya, int asize, const void *keyb, int bsize)
{
    int64_t tmpval = keya - keyb;
    return tmpval;
}
int rbSampleTraversalUint(const void *key, int keysize, const void *value, int valsize)
{
    logdebug("key=%lu, value=%lu", (uint64_t)key, (uint64_t)value);
    return 1;
}
struct rbtreeManagerStruct rbMngInstanceUint;

struct structDataValueInform
{
    char key[16];
    char value[16];
};
int rbSampleCompareString(const void *keya, int asize, const void *keyb, int bsize)
{
    return strcmp(keya, keyb);
}
int rbSampleTraversalString(const void *key, int keysize, const void *value, int valsize)
{
    struct structDataValueInform *tmpval = (struct structDataValueInform *)value;
    // logdebug("%p:%d", value, valsize);
    logdebug("key=%s, value.key=%s, value.value=%s", (char *)key, tmpval->key, tmpval->value);
    return 1;
}
struct rbtreeManagerStruct rbMngInstanceString;
int main(int argc, char **argv)
{
    srand(time(NULL));
    if (0)
    {
        uint64_t tmpval;
        uint32_t tmpvalsize;
        int tmpflag;
        rbtreeRootInit(&rbMngInstanceUint, rbSampleCompareUint, rbSampleTraversalUint);
        for (uint64_t i = 0; i < rbtreeCheckSize; i++)
        {
            uint64_t tmpval = rand() % 1000;
            // 用户数据为数字， 不用分配空间， 不用释放
            rbtreeInsertOperate(&rbMngInstanceUint, (void *)i, 0, (void *)tmpval, 0);
        }
        // 用户数据为数字， 不用分配空间， 不用释放
        rbtreeReplaceOperate(&rbMngInstanceUint, (void *)5, 0, (void *)65466, 0, NULL);

        rbtreeTraversalRoot(&rbMngInstanceUint, 1);
        tmpflag = rbtreeRootFree(&rbMngInstanceUint);
        logdebug("free managor, flag=%d", tmpflag);

        tmpflag = rbtreeFindWithErase(&rbMngInstanceUint, (void *)4, 0, (void **)&tmpval, &tmpvalsize, 0);
        logdebug("flag=%d, find value=%lu, size=%u", tmpflag, tmpval, tmpvalsize);
        // 用户数据为数字， 不用分配空间， 不用释放
        tmpflag = rbtreeGetRootWithErase(&rbMngInstanceUint, (void **)&tmpval, &tmpvalsize, 1);
        logdebug("flag=%d, find value=%lu, size=%u", tmpflag, tmpval, tmpvalsize);
        // 用户数据为数字， 不用分配空间， 不用释放
        tmpflag = rbtreeGetLeftesWithErase(&rbMngInstanceUint, (void **)&tmpval, &tmpvalsize, 1);
        logdebug("flag=%d, find value=%lu, size=%u", tmpflag, tmpval, tmpvalsize);
        // 用户数据为数字， 不用分配空间， 不用释放
        tmpflag = rbtreeGetRightesWithErase(&rbMngInstanceUint, (void **)&tmpval, &tmpvalsize, 1);
        logdebug("flag=%d, find value=%lu, size=%u", tmpflag, tmpval, tmpvalsize);
        rbtreeTraversalRoot(&rbMngInstanceUint, 1);
        while (1)
        {
            tmpflag = rbtreeGetRootWithErase(&rbMngInstanceUint, (void **)&tmpval, &tmpvalsize, 1);
            if (tmpflag > 0)
            {
                logdebug("flag=%d, find value=%lu, size=%u", tmpflag, tmpval, tmpvalsize);
            }
            else
            {
                logdebug("flag=%d", tmpflag);
                break;
            }
        }
        tmpflag = rbtreeRootFree(&rbMngInstanceUint);
        logdebug("free managor, flag=%d", tmpflag);
    }
    if (1)
    {
        struct structDataValueInform *tmpdata;
        char tmpfindkey[16];
        uint32_t tmpdatasize;
        int tmpflag;
        void *olddata;
        rbtreeRootInit(&rbMngInstanceString, rbSampleCompareString, rbSampleTraversalString);
        for (uint64_t i = 0; i < rbtreeCheckSize; i++)
        {
            // 分配空间插入
            tmpdata = malloc(sizeof(struct structDataValueInform));
            snprintf(tmpdata->key, sizeof(tmpdata->key), "%08lu-hc", i);
            snprintf(tmpdata->value, sizeof(tmpdata->value), "lx%08lu", i);
            rbtreeInsertOperate(&rbMngInstanceString, (void *)tmpdata->key, strlen(tmpdata->key) + 1, (void *)tmpdata,
                                sizeof(struct structDataValueInform));
        }

        // 分配空间替换
        tmpdata = malloc(sizeof(struct structDataValueInform));
        snprintf(tmpdata->key, sizeof(tmpdata->key), "%08d-hc", 4);
        snprintf(tmpdata->value, sizeof(tmpdata->value), "lx%08d", 999);
        tmpflag = rbtreeReplaceOperate(&rbMngInstanceString, (void *)tmpdata->key, strlen(tmpdata->key) + 1, (void *)tmpdata,
                                       sizeof(struct structDataValueInform), &olddata);
        if (tmpflag > 0)
        {
            logdebug("flag=%d, key=%s, value=%s", tmpflag, tmpdata->key, tmpdata->value);
        }
        else
        {
            logdebug("flag=%d", tmpflag);
            free(tmpdata);
        }

        // 查找,不释放
        snprintf(tmpfindkey, sizeof(tmpfindkey), "%08d-hc", 6);
        tmpflag = rbtreeFindWithErase(&rbMngInstanceString, tmpfindkey, sizeof(tmpfindkey), (void **)&tmpdata, &tmpdatasize, 0);
        if (tmpflag > 0)
        {
            logdebug("flag=%d, key=%s, value=%s", tmpflag, tmpdata->key, tmpdata->value);
        }
        else
        {
            logdebug("flag=%d", tmpflag);
        }

        //遍历二叉树
        rbtreeTraversalRoot(&rbMngInstanceString, 1);

        //释放管理器失败。
        tmpflag = rbtreeRootFree(&rbMngInstanceString);
        logdebug("free managor, flag=%d", tmpflag);

        //一直删除根节点，并释放用户数据，直到二叉树为空。
        while (1)
        {
            tmpflag = rbtreeGetRootWithErase(&rbMngInstanceString, (void **)&tmpdata, &tmpdatasize, 1);
            if (tmpflag > 0)
            {
                logdebug("flag=%d, key=%s, value=%s", tmpflag, tmpdata->key, tmpdata->value);
                free(tmpdata);
            }
            else
            {
                logdebug("flag=%d", tmpflag);
                break;
            }
        }
        //释放管理器失败。
        rbtreeRootFree(&rbMngInstanceString);
        logdebug("free managor, flag=%d", tmpflag);
    }
    return 0;
}
